Skip to main content

Network Object Linking

Network Object Linkers (or NOLs), are the central part of the General Network Object Management (or GNOM) system.

A NOL is a class that registers Network Objects and who is able to find a registered network object using its reference. NOLs also ensures to know if its registered references are also known, or not on other engines.

Architecture

The Network Object Linkage operates in a tree architecture.
An object linker can contain lower-level linkers, and when a request is performed on a linker, its implementation is free to decide to delegate the request to its children.
The root linker of the linker tree is the General Network Object Linker (or GNOL). This special linker contains sub root linkers that can be defined by the user.

Users can use any linkers in the tree, but the Persistence System directly starts from the GNOL to retrieve the objects.

Here is an architecture diagram example of the GNOL tree.

GNOL
'@'
GNOL...
Root Linker A
'@A'
Root Linker A...
Sub linker B
'@A/B'
Sub linker B...
Sub linker C
'@A/C'
Sub linker C...
Object 1
'@A/B/1'
Object 1...
Object 2
'@A/B/2'
Object 2...
Object 1
'@A/C/1'
Object 1...
Object 2
'@A/C/2'
Object 2...
Root Linker B
'@B'
Root Linker B...
Object 1
'@B/1'
Object 1...

Their roles in the persistence system.

Serialization is a very important issue, and when you design an application and wants it to communicate between the server and / or other connected clients, the way that you'll choose how to send data is a considerable question.
The Framework's Persistence System is autonomous enough to support almost any object serialization / deserialization, but it still needs some rules for objects that must receive special handling.
Network Objects are those objects that receive special handling, and the most of the time, you just want you network objects to get reused in the deserialization process, that's why you usually reuse a linker, such as the MapNetworkObjectLinker as you just want somewhere to put your objects.

In fact, the real first interest in a custom linker is when you want to perform initialization procedures when a Network Object handleable by your linker gets deserialized.
Second interest is when you have a certain data structure (let's say a database) and wants it to be used in the GNOL.

Implementation

In this part, we'll take a look at how to implement a Network Object Linker.

Here is the Network Object Linker UML diagram:

NetworkObjectLinker[R extends NetworkObjectReference]
NetworkObjectLinker[R extends NetworkObjectReference]
+ findObject(R): Option[NetworkObject[_ extends R]]
+ findObject(R): Option[NetworkObject[_ extends R]]
Extends
Extends
NetworkPresenceHandler[R extends NetworkObjectReference]
NetworkPresenceHandler[R extends NetworkObjectReference]
+ getPresence(R): NetworkObjectPresence
+ isPresentOnEngine(String, R): Boolean
+ getPresence(R): NetworkObjectPresence...

As you can see, an Object Linker is also a presence handler for its registered references. If you ever tried to implement the NetworkObjectLinker you must have been surprised to see that you had to implement getPresence(R) and isPresentOnEngine(String, R). Which must have confused you because you don't know how to handle your references presences.

AbstractNetworkPresenceHandler

Any implementation of the NetworkObjectLinker trait should also extend the AbstractNetworkPresenceHandler* abstract class that will implement all the presence handling and let you implement the findObject(R) method.

class DatabaseLinker(omc: ObjectManagementChannel, db: Connection) extends AbstractNetworkPresenceHandler[DatabaseObjectReference](omc, null) with NetworkObjectLinker[DatabaseObjectReference] {
override def findObject(ref: DatabaseObjectReference): Option[NetworkObject[_ <: DatabaseObjectReference] = {
//use the database connection to retrieve the object
}
}

By extending this class you'll find out that its constructor needs an ObjectManagementChannel and a nullable parent linker.
If your linker is a root linker, parent must be null. the ObjectManagementChannel is initially accessible only when supplying a root linker to the GNOL.

Register the linker in the GNOL

val linker: DatabaseLinker = gnol.addRootLinker(omc => new DatabaseLinker(omc))
linker.findObject(DatabaseObjectReference(...)) match {
case Some(X) => ...
case None => ...
}